/**
 * Copyright 2007 Igor Chaves Cananéa
 *
 * This file is part of PBSFW
 *
 * PBSFW is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; version 2 of the License.
 *
 * PBSFW is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */
#ifndef _STATISTIC_H_
#define _STATISTIC_H_

#include <vector>
#include <map>
using namespace std;

namespace statistic {
typedef map <double,double> NQTable;
typedef pair <double,double> NQPair;

// This class defines methods to provide statistics about samples
	class Statistic {
		private:
			double min;
			double max;
			double sum;
			double squareSum;
			unsigned size;
			double confidenceLevel;
			double accuracy;
			vector<double> *sample;
			static NQTable normalQuantileTable;
			class Filler {
				public:
					Filler() {
						Statistic::fillNormalQuantileTable();
					}
			};
			static Filler filler;

			double calculateMean() const ;
			double calculateStandardDeviation() const;
			double calculateConfidenceInterval() const;
			double calculatePrecision() const;
			int calculateRequiredNumberOfReplications(double accuracy);
			static void fillNormalQuantileTable();

		public:
			Statistic(bool accumulated = true);
			~Statistic();

			void addObservation(double value);

			const vector<double> &getSamples() const {
				return *this->sample;
			}

			// This method returns the sample size
			// (i.e., the number of observations within the sample)
			unsigned getSampleSize() const {
				return this->size;
			}

			// Returns the minimal observation of the sample
			double getSampleMin() const {
				return this->min;
			}

			// Returns the maximal observation of the sample
			double getSampleMax() const {
				return this->max;
			}

			// Returns the sample mean
			double getSampleMean() const {
				return this->calculateMean();
			}

			// Returns the sample standard deviation
			double getSampleStandardDeviation() const {
				return this->calculateStandardDeviation();
			}

			// Returns the confidence interval for the sample mean based
			// on the default confidence level
			double getConfidenceInterval() const {
				return this->calculateConfidenceInterval();
			}

			// Returns the precision of the default confidence interval
			double getPrecision() const {
				return this->calculatePrecision();
			}

			// Returns the number of replications required to achieve the
			// desired confidence level and accuracy
			int getRequiredNumberOfReplications(double accuracy) {
				return this->calculateRequiredNumberOfReplications(accuracy);
			}

			int getRequiredNumberOfReplications() {
				return this->calculateRequiredNumberOfReplications(this->accuracy);
			}

			//Returns the confidence level
			double getConfidenceLevel() const {
				return this->confidenceLevel;
			}

			//Returns a sample by his index
			double getSampleByIndex(int index) const {
				return (*this->sample)[index];
			}

			// Sets the confidence level value
			void setConfidenceLevel(double confidenceLevel) {
				this->confidenceLevel = confidenceLevel;
			}

			void setAccuracy(double accuracy) {
				this->accuracy = accuracy;
			}

			double getAccuracy() const {
				return this->accuracy;
			}

			// Resets the sample (i.e., deletes all the observations of the sample)
			void resetSample();
	};
};

#endif
